/**
 * 手势锁屏插件
 * varstion 1.0.5
 * by Houfeng
 * Houfeng@DCloud.io
 */

(function ($, doc) {

    var touchSupport = ('ontouchstart' in document);
    var startEventName = touchSupport ? $.EVENT_START : 'mousedown';
    var moveEventName = touchSupport ? $.EVENT_MOVE : 'mousemove';
    var endEventName = touchSupport ? $.EVENT_END : 'mouseup';
    var lockerHolderClassName = $.className('locker-holder');
    var lockerClassName = $.className('locker');

    var styleHolder = doc.querySelector('head') || doc.querySelector('body');
    styleHolder.innerHTML += "<style>.mui-locker-holder{overflow:hidden;position:relative;padding:0px;}.mui-locker-holder canvas{width:100%;height:100%;}</style>";

    var times = 2;

    function getElementLeft(element) {
        var actualLeft = element.offsetLeft;
        var current = element.offsetParent;
        while (current !== null) {
            actualLeft += current.offsetLeft;
            current = current.offsetParent;
        }
        return actualLeft;
    }

    function getElementTop(element) {
        var actualTop = element.offsetTop;
        var current = element.offsetParent;
        while (current !== null) {
            actualTop += current.offsetTop;
            current = current.offsetParent;
        }
        return actualTop;
    }

    //定义 Locker 类
    var Locker = $.Locker = $.Class.extend({
        R: 26,
        CW: 400,
        CH: 320,
        OffsetX: 30,
        OffsetY: 30,

        /**
         * 构造函数
         * */
        init: function (holder, options) {
            var self = this;
            if (!holder) {
                throw "构造 Locker 时缺少容器元素";
            }
            self.holder = holder;
            //
            options = options || {};
            options.callback = options.callback || options.done || $.noop;
            options.times = options.times || times;
            self.options = options;
            self.holder.innerHTML = '<canvas></canvas>';
            //
            self.holder.classList.add(lockerHolderClassName);
            //初始化
            var canvas = self.canvas = $.qsa('canvas', self.holder)[0];
            canvas.on = canvas.addEventListener || function (name, handler, capture) {
                    canvas.attachEvent('on' + name, handler, capture);
                };
            canvas.off = canvas.removeEventListener || function (name, handler, capture) {
                    canvas.detachEvent('on' + name, handler, capture);
                };
            //
            if (self.options.width) self.holder.style.width = self.options.width + 'px';
            if (self.options.height) self.holder.style.height = self.options.height + 'px';
            self.CW = self.options.width || self.holder.offsetWidth || self.CW;
            self.CH = self.options.height || self.holder.offsetHeight || self.CH;
            //处理 “宽、高” 等数值, 全部扩大 times 倍
            self.R *= self.options.times;
            self.CW *= self.options.times;
            self.CH *= self.options.times;
            self.OffsetX *= self.options.times;
            self.OffsetY *= self.options.times;
            //
            canvas.width = self.CW;
            canvas.height = self.CH;
            var cxt = self.cxt = canvas.getContext("2d");
            //两个圆之间的外距离 就是说两个圆心的距离去除两个半径
            var X = (self.CW - 2 * self.OffsetX - self.R * 2 * 3) / 2;
            var Y = (self.CH - 2 * self.OffsetY - self.R * 2 * 3) / 2;
            self.pointLocationArr = self.caculateNinePointLotion(X, Y);
            self.initEvent(canvas, cxt, self.holder);
            //console.log(X);
            self.draw(cxt, self.pointLocationArr, [], null);
            setTimeout(function () {
                self.draw(cxt, self.pointLocationArr, [], null);
            }, 0);
        },

        /**
         * 计算
         */
        caculateNinePointLotion: function (diffX, diffY) {
            var self = this;
            var Re = [];
            for (var row = 0; row < 3; row++) {
                for (var col = 0; col < 3; col++) {
                    var Point = {
                        X: (self.OffsetX + col * diffX + (col * 2 + 1) * self.R),
                        Y: (self.OffsetY + row * diffY + (row * 2 + 1) * self.R)
                    };
                    Re.push(Point);
                }
            }
            return Re;
        },

        /**
         * 绘制
         */
        draw: function (cxt, _PointLocationArr, _LinePointArr, touchPoint) {
            var self = this;
            var R = self.R;
            if (_LinePointArr.length > 0) {
                cxt.beginPath();
                for (var i = 0; i < _LinePointArr.length; i++) {
                    var pointIndex = _LinePointArr[i];
                    cxt.lineTo(_PointLocationArr[pointIndex].X, _PointLocationArr[pointIndex].Y);
                }
                cxt.lineWidth = (self.options.lindeWidth || 2) * self.options.times;
                cxt.strokeStyle = self.options.lineColor || "#999"; //连结线颜色
                cxt.stroke();
                cxt.closePath();
                if (touchPoint != null) {
                    var lastPointIndex = _LinePointArr[_LinePointArr.length - 1];
                    var lastPoint = _PointLocationArr[lastPointIndex];
                    cxt.beginPath();
                    cxt.moveTo(lastPoint.X, lastPoint.Y);
                    cxt.lineTo(touchPoint.X, touchPoint.Y);
                    cxt.stroke();
                    cxt.closePath();
                }
            }
            for (var i = 0; i < _PointLocationArr.length; i++) {
                var Point = _PointLocationArr[i];
                cxt.fillStyle = self.options.ringColor || "#888"; //圆圈边框颜色
                cxt.beginPath();
                cxt.arc(Point.X, Point.Y, R, 0, Math.PI * 2, true);
                cxt.closePath();
                cxt.fill();
                cxt.fillStyle = self.options.fillColor || "#f3f3f3"; //圆圈填充颜色
                cxt.beginPath();
                cxt.arc(Point.X, Point.Y, R - ((self.options.ringWidth || 2) * self.options.times), 0, Math.PI * 2, true);
                cxt.closePath();
                cxt.fill();
                if (_LinePointArr.indexOf(i) >= 0) {
                    cxt.fillStyle = self.options.pointColor || "#777"; //圆圈中心点颜色
                    cxt.beginPath();
                    cxt.arc(Point.X, Point.Y, R - ((self.options.pointWidth || 16) * self.options.times), 0, Math.PI * 2, true);
                    cxt.closePath();
                    cxt.fill();
                }
            }
        },

        isPointSelect: function (touches, linePoint) {
            var self = this;
            for (var i = 0; i < self.pointLocationArr.length; i++) {
                var currentPoint = self.pointLocationArr[i];
                var xdiff = Math.abs(currentPoint.X - touches.elementX);
                var ydiff = Math.abs(currentPoint.Y - touches.elementY);
                var dir = Math.pow((xdiff * xdiff + ydiff * ydiff), 0.5);
                if (dir < self.R) {
                    if (linePoint.indexOf(i) < 0) {
                        linePoint.push(i);
                    }
                    break;
                }
            }
        },

        initEvent: function (canvas, cxt, holder) {
            var self = this;
            var linePoint = [];
            var isDown = false; //针对鼠标事件
            //start
            self._startHandler = function (e) {
                e.point = event.changedTouches ? event.changedTouches[0] : event;
                e.point.elementX = (e.point.pageX - getElementLeft(holder)) * self.options.times;
                e.point.elementY = (e.point.pageY - getElementTop(holder)) * self.options.times;
                self.isPointSelect(e.point, linePoint);
                isDown = true;
            };
            canvas.on(startEventName, self._startHandler, false);
            //move
            self._moveHanlder = function (e) {
                if (!isDown) return;
                e.preventDefault();
                e.point = event.changedTouches ? event.changedTouches[0] : event;
                e.point.elementX = (e.point.pageX - getElementLeft(holder)) * self.options.times;
                e.point.elementY = (e.point.pageY - getElementTop(holder)) * self.options.times;
                var touches = e.point;
                self.isPointSelect(touches, linePoint);
                cxt.clearRect(0, 0, self.CW, self.CH);
                self.draw(cxt, self.pointLocationArr, linePoint, {
                    X: touches.elementX,
                    Y: touches.elementY
                });
            };
            canvas.on(moveEventName, self._moveHanlder, false);
            //end
            self._endHandler = function (e) {
                e.point = event.changedTouches ? event.changedTouches[0] : event;
                e.point.elementX = (e.point.pageX - getElementLeft(holder)) * self.options.times;
                e.point.elementY = (e.point.pageY - getElementTop(holder)) * self.options.times;
                cxt.clearRect(0, 0, self.CW, self.CH);
                self.draw(cxt, self.pointLocationArr, linePoint, null);
                //事件数据
                var eventData = {
                    sender: self,
                    points: linePoint
                };
                /*
                 * 回调完成事件
                 *
                 * 备注:
                 * 比较理想的做法是为 Locker 的实例启用事件机制，比如 locker.on('done',handler);
                 * 在 mui 没有完整的公共事件模块前，此版本中 locker 实例暂通过 options.callback 处理
                 */
                self.options.callback(eventData);
                //触发声明的DOM的自定义事件(暂定 done 为事件名，可以考虑更有针对的事件名 )
                $.trigger(self.holder, 'done', eventData);
                //-
                linePoint = [];
                isDown = false;
            };
            canvas.on(endEventName, self._endHandler, false);
        },

        pointLocationArr: [],

        /**
         * 清除图形
         * */
        clear: function () {
            var self = this;
            //self.pointLocationArr = [];
            if (self.cxt) {
                self.cxt.clearRect(0, 0, self.CW, self.CH);
                self.draw(self.cxt, self.pointLocationArr, [], {
                    X: 0,
                    Y: 0
                });
            }
        },

        /**
         * 释放资源
         * */
        dispose: function () {
            var self = this;
            self.cxt = null;
            self.canvas.off(startEventName, self._startHandler);
            self.canvas.off(moveEventName, self._moveHandler);
            self.canvas.off(endEventName, self._endHandler);
            self.holder.innerHTML = '';
            self.canvas = null;
        }
    });

    //添加 locker 插件
    $.fn.locker = function (options) {
        //遍历选择的元素
        this.each(function (i, element) {
            if (element.locker) return;
            if (options) {
                element.locker = new Locker(element, options);
            } else {
                var optionsText = element.getAttribute('data-locker-options');
                var _options = optionsText ? JSON.parse(optionsText) : {};
                _options.lineColor = element.getAttribute('data-locker-line-color') || _options.lineColor;
                _options.ringColor = element.getAttribute('data-locker-ring-color') || _options.ringColor;
                _options.fillColor = element.getAttribute('data-locker-fill-color') || _options.fillColor;
                _options.pointColor = element.getAttribute('data-locker-point-color') || _options.pointColor;
                _options.width = element.getAttribute('data-locker-width') || _options.width;
                _options.height = element.getAttribute('data-locker-height') || _options.height;
                element.locker = new Locker(element, _options);
            }
        });
        return this[0] ? this[0].locker : null;
    };

    //自动处理 class='mui-locker' 的 dom
    try {
        $('.' + lockerClassName).locker();
    } catch (ex) {
    }
    $.ready(function () {
        $('.' + lockerClassName).locker();
    });

}(mui, document));